--****
-- zlib.e - Simple euphoria wrapper around zlib from [[http://www.zlib.net| zlib.net]]
--
-- Author: Jeremy Cowgar jeremy@cowgar.com
--
--since zlib can only do zip and gz and none of later formats
--probably cannot handle password protected files or maximal compression
--versions earlier than 1.2 not supported
--probably eventually replace with 7zip wrapper

namespace zlib

include std/dll.e
include std/machine.e
include qt/wrap_helpers.e

ifdef WINDOWS then
	constant lib = open_dll("zlib1.dll")
elsifdef UNIX then
	constant lib = open_dll("libz.so")
elsedef
	puts(2, "OS not supported\n")
	abort(1)
end ifdef


-----------------------------------------------------------------------------------------
--
-- Types/Constants
--
-----------------------------------------------------------------------------------------

public type gzfile(object o)
	return atom(o)
end type

public constant
	Z_NO_FLUSH            =  0,
	Z_PARTIAL_FLUSH       =  1,
	Z_SYNC_FLUSH          =  2,
	Z_FULL_FLUSH          =  3,
	Z_FINISH              =  4,
	Z_BLOCK               =  5,
	Z_OK                  =  0,
	Z_STREAM_END          =  1,
	Z_NEED_DICT           =  2,
	Z_ERRNO               = -1,
	Z_STREAM_ERROR        = -2,
	Z_DATA_ERROR          = -3,
	Z_MEM_ERROR           = -4,
	Z_BUF_ERROR           = -5,
	Z_VERSION_ERROR       = -6,
	Z_NO_COMPRESSION      =  0,
	Z_BEST_SPEED          =  1,
	Z_BEST_COMPRESSION    =  9,
	Z_DEFAULT_COMPRESSION = -1,
	Z_FILTERED            =  1,
	Z_HUFFMAN_ONLY        =  2,
	Z_RLE                 =  3,
	Z_FIXED               =  4,
	Z_DEFAULT_STRATEGY    =  0,
	Z_BINARY              =  0,
	Z_TEXT                =  1,
	Z_ASCII               =  1,
	Z_UNKNOWN             =  2,
	Z_DEFLATED            =  8,
	Z_NULL                =  0,
	Z_SEEK_SET            =  0,
	Z_SEEK_CUR            =  1,
	Z_SEEK_END            =  2

-----------------------------------------------------------------------------------------
--
-- Helpers
--
-----------------------------------------------------------------------------------------

function alloc(integer len)
	atom h = allocate(len)
	mem_set(h, 0, len)
	return h
end function

-----------------------------------------------------------------------------------------
--
-- Wrappers
--
-----------------------------------------------------------------------------------------

constant
	f_zlibVersion = define_c_func(lib,  stdcall&"zlibVersion", {}, C_POINTER),
	f_gzopen  = define_c_func(lib,  stdcall&"gzopen",  { C_POINTER, C_POINTER }, C_POINTER),
	f_gzputs  = define_c_func(lib,  stdcall&"gzputs",  { C_POINTER, C_POINTER }, C_INT),
	f_gzgets  = define_c_func(lib,  stdcall&"gzgets",  { C_POINTER, C_POINTER, C_INT }, C_POINTER),
	f_gzread  = define_c_func(lib,  stdcall&"gzread",  { C_POINTER, C_POINTER, C_INT }, C_INT),
	f_gzwrite = define_c_func(lib,  stdcall&"gzwrite", { C_POINTER, C_POINTER, C_INT }, C_INT),
	f_gzseek  = define_c_func(lib,  stdcall&"gzseek",  { C_POINTER, C_LONG, C_INT }, C_LONG),
	f_gztell  = define_c_func(lib,  stdcall&"gztell",  { C_POINTER }, C_LONG),
	f_gzflush = define_c_func(lib,  stdcall&"gzflush", { C_POINTER, C_INT }, C_INT),
	f_gzclose = define_c_func(lib,  stdcall&"gzclose", { C_POINTER }, C_INT)

public function zlibVersion()
	atom hVersion = c_func(f_zlibVersion, {})
	return peek_string(hVersion)
end function

public function gzopen(sequence filename, sequence mode)
	atom
		hFilename = allocate_string(filename),
		hMode = allocate_string(mode)

	atom ret = c_func(f_gzopen, { hFilename, hMode })

	free(hFilename)
	free(hMode)

	return ret
end function

public function gzputs(gzfile fh, sequence buf)
	atom hBuf = allocate_string(buf)

	integer ret = c_func(f_gzputs, { fh, hBuf })

	free(hBuf)

	return ret
end function

public function gzgets(gzfile fh, integer len)
	atom hBuf = allocate(len * 4)

	atom status = c_func(f_gzgets, { fh, hBuf, len })

	sequence ret = peek_string(hBuf)

	return ret
end function

public function gzwrite(gzfile fh, sequence buf)
	atom hBuf = alloc(length(buf))

	poke(hBuf, buf)

	integer ret = c_func(f_gzwrite, { fh, hBuf, length(buf) })

	free(hBuf)

	return ret
end function

public function gzread(gzfile fh, integer len)
	atom hBuf = alloc(len)

	object count = c_func(f_gzread, { fh, hBuf, len })

	-- If we have actually read data, then return the data instead of gzread status
	sequence buf = ""
	if count > 0 then
		sequence data = peek({ hBuf, count })
		free(hBuf)
		return data
	end if

	return count
end function

public function gzseek(gzfile fh, integer offset, integer whence)
	return c_func(f_gzseek, { fh, offset, whence })
end function

public function gztell(gzfile fh)
	return c_func(f_gztell, { fh })
end function

public function gzflush(gzfile fh, integer flush)
	return c_func(f_gzflush, { fh, flush })
end function

public function gzclose(gzfile fh)
	return c_func(f_gzclose, { fh })
end function
